package com.ruibo.modules.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.ruibo.constants.UserConstants;
import com.ruibo.exception.BadRequestException;
import com.ruibo.utils.PageUtil;
import com.ruibo.utils.QueryHelp;
import com.ruibo.utils.StringUtils;
import com.ruibo.modules.system.domain.SysDept;
import com.ruibo.modules.system.domain.SysPost;
import com.ruibo.modules.system.domain.SysRole;
import com.ruibo.modules.system.domain.SysUser;
import com.ruibo.modules.system.repository.SysDeptRepository;
import com.ruibo.modules.system.repository.SysPostRepository;
import com.ruibo.modules.system.repository.SysRoleRepository;
import com.ruibo.modules.system.repository.SysUserRepository;
import com.ruibo.modules.system.service.SysPostService;
import com.ruibo.modules.system.service.SysRoleService;
import com.ruibo.modules.system.service.dto.SysUserDto;
import com.ruibo.modules.system.criteria.UserQueryCriteria;
import com.ruibo.modules.system.service.mapper.SysPostMapper;
import com.ruibo.modules.system.service.mapper.SysRoleMapper;
import com.ruibo.modules.system.service.mapper.SysUserMapper;
import com.ruibo.modules.system.service.SysUserService;
import com.ruibo.utils.UpdateUtil;
import org.springframework.cache.annotation.*;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.Supplier;

/**
 * (SysUser)表服务实现类
 *  https://blog.csdn.net/justry_deng/article/details/89283664
 * @author sunfeng
 * @since 2020-04-17 13:33:19
 */
//现在每一个缓存注解都需要填写cacheNames 我们可以在类上配置
//@CacheConfig(cacheNames = "user")
@Service("sysUserService")
public class SysUserServiceImpl implements SysUserService {
    @Resource
    private SysUserRepository sysUserRepository;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysDeptRepository sysDeptRepository;

    @Resource
    private SysPostService sysPostService;

    @Resource
    private SysPostRepository sysPostRepository;

    @Resource
    private SysPostMapper sysPostMapper;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysRoleRepository sysRoleRepository;

    @Resource
    private SysRoleMapper sysRoleMapper;


    /**
     * 根据id查询用户信息
     * 在目标方法执行前，会根据key先去缓存中查询看是否有数据，有就直接
     * 返回缓存中的key对应的value值。不再执行目标方法；无则执行目标方法，并将方法的返回值
     * 作为value，并以键值对的形式存入缓存
     *
     * @param userId /
     * @return
     */
    @Override
    //condition作用时机在：缓存注解检查缓存中是否有对应的key-value 之前
    @Cacheable(cacheNames = "user", key = "'id:'+#userId")
    public SysUserDto queryById(Long userId) {
        SysUserDto sysUserDto = this.sysUserMapper.toDto(this.sysUserRepository.getOne(userId));
        sysUserDto.setDeptId(this.sysUserRepository.getOne(userId).getDept().getId());
        return sysUserDto;
    }

    @Override
    public List<SysUserDto> findAll() {
        return this.sysUserMapper.toDto(this.sysUserRepository.findAll());

    }

    /**
     * 根据用户名查询用户信息
     *
     * @param username
     * @return
     */
    @Override
    public SysUserDto findByName(String username) {
        return this.sysUserMapper.toDto(
                this.sysUserRepository.findByUserName(username));
    }

    /**
     * 根据查询条件查获取用户的分页信息
     *
     * @param criteria
     * @param pageable
     * @return
     */
    @Override
    public Object queryAll(UserQueryCriteria criteria, Pageable pageable) {
        Page<SysUser> page = sysUserRepository.findAll((root, criteriaQuery, criteriaBuilder) ->
                QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(sysUserMapper::toDto));
    }

    @Override
    public Object queryAllByLimit(int offset, int limit) {
        return PageUtil.toPage(this.sysUserRepository.findAll(PageRequest.of((offset - 1)
                * limit, limit)).map(sysUserMapper::toDto));

    }


    @Override
    @Transactional
    public SysUserDto save(SysUserDto sysUser) {

        SysUser user = new SysUser();
        UpdateUtil.copyNullProperties(sysUser, user);
        SysDept sysDept = sysDeptRepository.getOne(sysUser.getDeptId());
        // 新增用户部门关联
        user.setDept(sysDept);

        // 用户关联职位
        List<SysPost> postList = sysPostRepository.findAllById(Arrays.asList(sysUser.getPostIds()));
        HashSet<SysPost> posts = new HashSet<>(postList);
        user.setSysPost(posts);
        // 用户关联角色
        List<SysRole> roleList = sysRoleRepository.findAllById(Arrays.asList(sysUser.getRoleIds()));
        HashSet<SysRole> sysRoles = new HashSet<>(roleList);
        user.setSysRoles(sysRoles);

        // 新增用户与角色管理
        return this.sysUserMapper.toDto(
                this.sysUserRepository.save(user));

    }

    /**
     * 更新的方法
     *
     * @param sysUser /
     * @return
     */
    @Override
    @Transactional
    @CachePut(cacheNames = "user", key = "'id:'+#sysUser.id")
    public SysUserDto update(SysUserDto sysUser) {
        //update 需要重新处理
        SysUser user = sysUserRepository.findById(sysUser.getId()).get();
        UpdateUtil.copyNullProperties(sysUser, user);
        if (ObjectUtil.isNotEmpty(sysUser.getPostIds())) {
            // 用户关联职位
            List<SysPost> postList = sysPostRepository.findAllById(Arrays.asList(sysUser.getPostIds()));
            HashSet<SysPost> posts = new HashSet<>(postList);
            user.setSysPost(posts);
        }
        if (ObjectUtil.isNotEmpty(sysUser.getRoleIds())) {
            // 用户关联角色
            List<SysRole> roleList = sysRoleRepository.findAllById(Arrays.asList(sysUser.getRoleIds()));
            HashSet<SysRole> sysRoles = new HashSet<>(roleList);
            user.setSysRoles(sysRoles);
        }
        //关联部门
        if(!ObjectUtil.isEmpty(sysUser.getDeptId())){
            SysDept sysDept = sysDeptRepository.findById(sysUser.getDeptId()).orElseGet(SysDept::new);
            user.setDept(sysDept);
        }
        SysUserDto sysUserDto = sysUserMapper.toDto(sysUserRepository.save(user));
        sysUserDto.setDeptId(sysUser.getDeptId());

        // 新增用户与角色管理
        return sysUserDto;
    }

    /**
     * @param userId /
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "user", key = "#p0", beforeInvocation = true)
    public boolean deleteById(Long userId) {

        try {
            this.sysUserRepository.deleteById(userId);
        } catch (Exception ex) {
            return false;
        }
        return true;

    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    public void checkUserAllowed(SysUserDto user) {
        sysUserRepository.findById(user.getId()).ifPresent(sysUser -> {
            if (StringUtils.isNotNull(sysUser.getId()) && sysUser.isAdmin()) {
                throw new BadRequestException("不允许操作超级管理员用户");
            }
        });

    }

    @Override
    public int updateUserStatus(SysUser user) {
        SysUser sysUser = sysUserRepository.getOne(user.getId());
        sysUser.setStatus(user.getStatus());
        sysUserRepository.save(sysUser);
        return 0;
    }

    /**
     * 根据用户名查询用户是否唯一
     *
     * @param userName 用户名称
     * @return
     */
    @Override
    public String checkUserNameUnique(String userName) {

        int count = sysUserRepository.countByUserName(userName);
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;

    }

    /**
     * 校验手机号码是否唯一
     *
     * @param phoneNumber 电话号码
     * @return 结果
     */
    @Override
    public String checkPhoneUnique(String phoneNumber) {

        int count = sysUserRepository.countByPhoneNumber(phoneNumber);
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public String checkEmailUnique(String email) {
        int count = sysUserRepository.countByEmail(email);
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 更具ids 批量删除
     *
     * @param userIds
     */
    @Override
    @Transactional
    public void deleteUserByIds(Long[] userIds) {
        //这里的删除需要先处理多对多的关系
        for (Long id : userIds) {
            SysUser sysUser = sysUserRepository.findById(id).get();
            sysUser.setSysRoles(null);
            sysUser.setSysPost(null);
            sysUserRepository.save(sysUser);
            sysUserRepository.deleteById(id);
        }
    }
}
